
#include <BTcpSocket>
#include <BTcpServer>
#include <WS2tcpip.h>
#include "member_BSocket.h"
#include "member_BTcpServer.h"

using namespace BWE;

#define member					(*(member_BTcpServer*)_ptr)
#define member_allocate()		_ptr = new member_BTcpServer(this)
#define member_release()		delete (member_BTcpServer*)_ptr

#ifdef _LINUX_
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

BTcpServer::BTcpServer()
{
	member_allocate();
	socket_member(this)->create(AF_INET, SOCK_STREAM, 0);
	socket_member(this)->setnonblock();
}
BTcpServer::~BTcpServer()
{
	socket_member(this)->destroy();
	member_release();
}

BTcpServer::Type BTcpServer::type() const
{
	return Type_TcpServer;
}

bool BTcpServer::bind(const BString& ip, int port)
{
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(ip.cstr());
	
	int ret = ::bind(socket_member(this)->socket, (sockaddr*)&addr, sizeof(addr));
	if(ret == -1)
	{
		perror("bind");
		return false;
	}
	return true;
}

bool BTcpServer::listen(int maximum)
{
	int ret = ::listen(socket_member(this)->socket, maximum);
	if(ret == -1)
	{
		perror("listen");
		return false;
	}
	return true;
}

BSocket::Notifier BTcpServer::select(double seconds) const
{
	fd_set rfds;
	fd_set wfds;
	fd_set efds;
	
	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_ZERO(&efds);
	
	FD_SET(socket_member(this)->socket, &rfds);
	//FD_SET(socket_member(this)->socket, &wfds);
	FD_SET(socket_member(this)->socket, &efds);

	timeval* ptv = 0;
	timeval tv;

	if(seconds >= 0)
	{
		tv.tv_sec = seconds;
		tv.tv_usec = (seconds - tv.tv_sec) * 1000000;
		ptv = &tv;
	}

	int ret = ::select(socket_member(this)->socket + 1, &rfds, &wfds, &efds, ptv);
	if(ret == -1)
	{
		perror("select");
		return BSocket::Notifier_Error;
	}
	if(FD_ISSET(socket_member(this)->socket, &rfds))
		return BSocket::Notifier_Read;
	if(FD_ISSET(socket_member(this)->socket, &wfds))
		return BSocket::Notifier_Write;
	if(FD_ISSET(socket_member(this)->socket, &efds))
		return BSocket::Notifier_Close;
	return BSocket::Notifier_None;
}


#endif

#ifdef _WINDOWS_SYSTEM_

BTcpServer::BTcpServer()
{
	member_allocate();
	socket_member(this)->create(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}
BTcpServer::~BTcpServer()
{
	socket_member(this)->destroy();
	member_release();
}

BTcpServer::Type BTcpServer::type() const
{
	return TcpServer;
}

bool BTcpServer::bind(const BString& ip, int port)
{
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	InetPton(AF_INET, ip.cstr(), &addr.sin_addr.s_addr);

	int ret = ::bind(socket_member(this)->sock, (sockaddr*)&addr, sizeof(addr));
	if(ret == SOCKET_ERROR)
	{
		int errorCode = WSAGetLastError();
		perror("bind");
		return false;
	}
	return true;
}
bool BTcpServer::listen(int maxApplyNumber)
{
	int ret = ::listen(socket_member(this)->sock, maxApplyNumber);
	if(ret == SOCKET_ERROR)
	{
		int errorCode = WSAGetLastError();
		perror("bind");
		return false;
	}
	socket_member(this)->state = State_Listening;
	return true;
}

BTcpSocket* BTcpServer::accept()
{
	BTcpSocket* tcpSocket = member.newConnection;
	if (member.newConnection)
	{
		member.newConnection = 0;
	}
	return tcpSocket;
}

#endif
